package taskit.datastructures;

import java.io.Serializable;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.GregorianCalendar;
import java.util.Calendar;
import java.util.LinkedList;

import taskit.customexceptions.WrongDateException;
import taskit.test.Log;

//@author A0087072A
public class Date implements Comparable<Date>, Serializable, ITaskItObject {

	public final static String NAME_CLASS = "Date";

	private static final long serialVersionUID = 1L;
	private static final int DEFAULT_INT = 0;

	private int year;
	private int month; // *NOTE*:: 0 - January, 11 - December
	private int day;
	private int hour; // *NOTE*:: 0 - 12 am, 23 - 11 pm
	private int mins;

	public Date() {
		year = month = day = hour = mins = DEFAULT_INT;
	}

	public Date(String date) throws ParseException {
		final String NAME_FUNCTION = ".Date(String date)";
		Log.add(NAME_CLASS + NAME_FUNCTION + ": date = " + date);

		boolean successfulParse = false;
		SimpleDateFormat dateFormat = null;
		for (String format : DATE_FORMATS) {
			try {
				dateFormat = new SimpleDateFormat(format);
				dateFormat.parse(date);
				Log.add(NAME_CLASS + NAME_FUNCTION + ": DATE_FORMAT = \""
						+ format + "\" passed");
				successfulParse = true;
				break;
			} catch (Exception e) {
				Log.add(NAME_CLASS + NAME_FUNCTION + ": DATE_FORMAT = \""
						+ format + "\" failed");
				continue;
			}
		}

		if (successfulParse) {
			Calendar temp = dateFormat.getCalendar();
			this.year = temp.get(Calendar.YEAR);
			this.month = temp.get(Calendar.MONTH);
			this.day = temp.get(Calendar.DAY_OF_MONTH);
			this.hour = temp.get(Calendar.HOUR_OF_DAY);
			this.mins = temp.get(Calendar.MINUTE);
			Log.add(NAME_CLASS + NAME_FUNCTION + ": completed successfully.");
		} else {
			throw new ParseException(
					RETURN_CODES_IN_ENGLISH[ERR_WRONG_DATE_FORMAT], 0);
		}
	}

	public Date(int year, int month, int day, int hour, int mins) {
		this.year = year;
		this.month = month;
		this.day = day;
		this.hour = hour;
		this.mins = mins;
	}

	public Date(int year, int month, int day) {
		this(year, month, day, DEFAULT_INT, DEFAULT_INT);
	}

	public static Date createDate(int year, int month, int day) throws WrongDateException {
		return createDate(year, month, day, DEFAULT_INT, DEFAULT_INT);
	}

	public int getYear() {
		return year;
	}

	public int getMonth() {
		return month;
	}

	public int getDay() {
		return day;
	}

	public int getHour() {
		return hour;
	}

	public int getMins() {
		return mins;
	}

	// Gets the current date
	public static Date currentDate() {
		GregorianCalendar date = new GregorianCalendar();
		try {
			return new Date(date.get(Calendar.YEAR), date.get(Calendar.MONTH),
					date.get(Calendar.DAY_OF_MONTH),
					date.get(Calendar.HOUR_OF_DAY), date.get(Calendar.MINUTE));
		} catch (Exception e) {
			System.out.println(e.getMessage());
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public int compareTo(Date date) {

		int result = this.year - date.getYear();
		if (result == 0) {
			result = this.month - date.getMonth();
			if (result == 0) {
				result = this.day - date.getDay();
				if (result == 0) {
					result = this.hour - date.getHour();
					if (result == 0) {
						result = this.mins - date.getMins();
					}
				}
			}
		}
		return result;
	}

	@Override
	
	public String toString() {
		String retval = "";
		String dayString = ((day == DEFAULT_INT) ? "00" : "" + day);
		while (dayString.length() != 2) {
			dayString = "0" + dayString;
		}
		String yearString = ((year == DEFAULT_INT) ? "0000" : "" + year);
		String monthString = ((month == DEFAULT_INT) ? "01" : "" + (month + 1));
		while (monthString.length() != 2) {
			monthString = "0" + monthString;
		}
		String hourString = ((hour == DEFAULT_INT) ? "00" : "" + hour);
		while (hourString.length() != 2) {
			hourString = "0" + hourString;
		}
		String minString = ((mins == DEFAULT_INT) ? "00" : "" + mins);
		while (minString.length() != 2) {
			minString = "0" + minString;
		}
		retval = dayString + monthString + yearString + hourString + minString;
		return retval;
	}

	public boolean equals(Date date) {
		if (this.compareTo(date) == 0)
			return true;
		else
			return false;
	}

	
	// @author A0098733R
	public static LinkedList<Date> getListDates(Date start, Date end) {

		LinkedList<Date> list = new LinkedList<Date>();
		Date date = start.extractDate();
		try {
			while (date.compareTo(end) <= 0) {
				list.add(date);
				GregorianCalendar cal = new GregorianCalendar(date.getYear(),
						date.getMonth(), date.getDay());
				cal.add(Calendar.DAY_OF_MONTH, 1);
				date = new Date(cal.get(Calendar.YEAR),
						cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH));
			}
		} catch (Exception e) {
			System.out.println(e.getMessage());
			e.printStackTrace();
		}
		return list;
	}
	
	public static Date createDate(int year, int month, int day, int hour,
			int mins) throws WrongDateException {
		SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy/HH/mm");
		sdf.setLenient(false);
		try {
			sdf.parse(day + "/" + (month + 1) + "/" + year + "/" + hour + "/"
					+ mins);
		} catch (Exception e) {
			throw new WrongDateException("Invalid date");
		}
		return new Date(year, month, day, hour,
				mins);
	}
	
	public Date extractDate() {
		try {
			return new Date(getYear(), getMonth(), getDay());
		} catch (Exception e) {
			System.out.println(e.getMessage());
			e.printStackTrace();
		}
		return null;
	}
}
